package cn.coldleaf.wiki.services.impl;

import cn.coldleaf.wiki.cache.AppCache;
import cn.coldleaf.wiki.configure.AppConfig;
import cn.coldleaf.wiki.errors.FileReadException;
import cn.coldleaf.wiki.errors.FileUploadException;
import cn.coldleaf.wiki.mappers.FileMapper;
import cn.coldleaf.wiki.mappers.UserMapper;
import cn.coldleaf.wiki.pojo.dto.FileUploadDto;
import cn.coldleaf.wiki.pojo.entity.FileEntity;
import cn.coldleaf.wiki.pojo.entity.UserEntity;
import cn.coldleaf.wiki.pojo.vo.FileVo;
import cn.coldleaf.wiki.pojo.vo.UploadVo;
import cn.coldleaf.wiki.services.StreamService;
import cn.coldleaf.wiki.utils.CaptchaUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 流处理Service
 * @datetime 2023/10/18 下午12:06
 * @user cold
 **/
@Slf4j
@Service
@AllArgsConstructor
public class StreamServiceImpl implements StreamService {
    private final CaptchaUtil captchaUtil;
    private final AppCache appCache;
    private final UserMapper userMapper;
    private final FileMapper fileMapper;
    private final AppConfig appConfig;

    /**
     * 获取文件
     *
     * @param userId
     * @param name   文件名称
     * @datetime 2023-10-17 15:03:38
     * @user cold
     **/
    @Override
    public void file(HttpServletResponse response,Long userId,String type,String name) {
        FileEntity entity = fileMapper.selectOne(new QueryWrapper<FileEntity>()
                .lambda()
                .eq(FileEntity::getType, type)
                .eq(FileEntity::getRealName, name)
                .last("limit 1")
        );
        if (entity == null){
            response.setStatus(HttpStatus.NOT_FOUND.value());
            response.setCharacterEncoding("UTF-8");
            return;
        }
        try {
            readFile(response,entity.getPath());
        } catch (IOException e) {
            throw new FileReadException(e);
        }
    }

    private void readFile(HttpServletResponse response, String filePath) throws IOException {
        FileChannel channel = FileChannel.open(Paths.get(filePath), StandardOpenOption.READ);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        ServletOutputStream os = response.getOutputStream();
        while (channel.read(buffer) != -1){
            buffer.flip();
            if (buffer.hasArray()) {
                os.write(buffer.array());
            }
            buffer.clear();
        }
        os.flush();
        channel.close();
    }

    /**
     * 获取验证码
     *
     * @param response
     * @datetime 2023-10-17 15:05:13
     * @user cold
     **/
    @Override
    public void captcha(HttpServletResponse response) {
        CaptchaUtil.Captcha captcha = captchaUtil.getCaptcha();
        try {
            String captchaId = UUID.randomUUID().toString();
            response.setHeader("X-CAPTCHA-ID", captchaId);
            appCache.put(captchaId,captcha.getCode(),3600000L);
            ImageIO.write(captcha.getImage(),"png",response.getOutputStream());
        } catch (IOException e) {
            log.error("输出图片流失败",e);
        }
    }

    /**
     * 上传文件
     *
     * @param dto
     * @datetime 2023-10-19 10:26:27
     * @user cold
     */
    @Override
    @Transactional
    public UploadVo upload(FileUploadDto dto) {
        UserEntity entity = userMapper.selectById(dto.getOperator());
        String type = getTargetDir(dto.getFile().getContentType());
        String homeDir = appConfig.getHomeDir();
        String baseDir = homeDir.substring(0,homeDir.lastIndexOf("/",homeDir.length() - 2)+1);
        String path = baseDir + entity.getHome() + type;
        String fileName = UUID.randomUUID().toString() + getFileSuffix(dto.getFile().getOriginalFilename());
        try {
            FileEntity file = new FileEntity();
            file.setName(dto.getFile().getOriginalFilename());
            file.setRealName(fileName);
            file.setType(type.replace("/",""));
            file.setPath(path+fileName);
            file.setAuth(dto.getAuth() != null ? dto.getAuth() : 1);
            file.setUserId(dto.getOperator());
            file.setDocId(dto.getDocId());
            file.setAddUser(dto.getOperator());
            file.setUpdateUser(dto.getOperator());
            fileMapper.insert(file);
            dto.getFile().transferTo(new File(path +fileName));
            UploadVo vo = new UploadVo();
            vo.setUrl("/file/"+type+fileName);
            return vo;
        }catch (IOException e){
            log.error("文件保存失败",e);
            throw new FileUploadException(e);
        }
    }

    private String getFileSuffix(String orgFileName){
        if (orgFileName == null){
            return "";
        }
        return orgFileName.substring(orgFileName.lastIndexOf("."),orgFileName.length());
    }

    private String getTargetDir(String contentType){
        if (contentType == null) {
            return "other/";
        }else if (contentType.startsWith("image")){
            return "image/";
        }else if (contentType.startsWith("video")){
            return "video/";
        }else if (contentType.startsWith("audio")){
            return "music/";
        }else {
            return "other/";
        }
    }

    /**
     * 下载文件
     *
     * @param userId
     * @param name   文件名
     * @datetime 2023-10-17 15:05:47
     * @user cold
     **/
    @Override
    public byte[] download(Long userId, String name) {
        return new byte[0];
    }

    /**
     * 删除指定文件
     *
     * @param type
     * @param realName
     * @datetime 2023-10-26 16:45:36
     * @user cold
     */
    @Override
    @Transactional
    public int removeFile(String type, String realName) {
        FileEntity entity = fileMapper.selectOne(new QueryWrapper<FileEntity>()
                .lambda()
                .eq(FileEntity::getType, type)
                .eq(FileEntity::getRealName, realName)
                .last("limit 1")
        );
        int ret = 0;
        if (entity != null){
            File file = new File(entity.getPath());
            if (file.exists()){
                ret = file.delete() ? 1 : 0;
            }
            if (ret == 1){//删除数据库记录
                fileMapper.deleteById(entity.getId());
            }
        }
        return ret;
    }

    /**
     * 获取文档资源列表
     *
     * @param docId
     * @datetime 2023-10-26 18:43:27
     * @user cold
     */
    @Override
    public List<FileVo> getByDoc(Long docId) {
        List<FileEntity> fileList = fileMapper.selectList(
                new QueryWrapper<FileEntity>()
                .lambda()
                .eq(FileEntity::getDocId,docId)
        );
        List<FileVo> vos = new ArrayList<>(fileList.size());
        for (FileEntity file : fileList) {
            vos.add(new FileVo(file));

        }
        return vos;
    }
}
